package com.beta.service.impl;


import com.baomidou.framework.service.impl.SuperServiceImpl;
import com.beta.dto.cart.*;
import com.beta.dto.order.OrderItemDto;
import com.beta.dto.product.ProductItemOptions;
import com.beta.dto.product.ProductPropertiesDto;
import com.beta.entity.CartItems;
import com.beta.entity.ProductItems;
import com.beta.entity.Users;
import com.beta.mapper.CartItemsMapper;
import com.beta.service.*;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


/**
 * CartItems 表数据服务层接口实现类
 */
@Service
public class CartItemsService extends SuperServiceImpl<CartItemsMapper, CartItems> implements ICartItemsService {

    @Autowired
    private IProductItemsService productItemsService;
    @Autowired
    private IUsersService usersService;
    @Autowired
    private IDateTimeService dbService;
    @Autowired
    private IProductPropertiesService productPropertiesService;
    @Autowired
    private IOrderItemsService orderItemsService;
    @Autowired
    private IReceiversService receiversService;

    @Override
    public List<CartItemDto> getCartItems(Integer userId) {
        if (Objects.isNull(userId)) {
            throw new ServiceException("E00113");
        }
        List<CartItemDto> cartItemDtos = baseMapper.getCartItems(userId);
        if (CollectionUtils.isEmpty(cartItemDtos)) {
            return Collections.emptyList();
        }
        List<Integer> productIds = cartItemDtos.stream().map(CartItemDto::getProductId).collect(Collectors.toList());
        List<Integer> productItemIds = cartItemDtos.stream().map(CartItemDto::getProductItemId).collect(Collectors.toList());
        Map<Integer, List<ProductPropertiesDto>> productPropertiesMap = productPropertiesService.getProductPropertiesBatch(productIds);
        Map<Integer, List<ProductItemOptions>> productItemOptionsMap = productItemsService.getProductItemOptionsBatch(productItemIds);
        for (CartItemDto cartItemDto : cartItemDtos) {
            cartItemDto.setProperties(productPropertiesMap.get(cartItemDto.getProductId()));
            cartItemDto.setOptions(productItemOptionsMap.get(cartItemDto.getProductItemId()));
        }
        return cartItemDtos;
    }

    @Override
    public CartProductItemDto addCartItem(Integer productItemId, Integer userId) {
        CartItems dbCartItem = selectOne(new CartItems().setProductItemId(productItemId).setUserId(userId));
        ProductItems productItem = productItemsService.selectById(productItemId);

        boolean existsCartItem = Objects.isNull(dbCartItem);
        if (existsCartItem) {
            createCartItem(productItem, userId);
        } else {
            updateCartItemQuantity(dbCartItem.getId(), productItem, dbCartItem.getQuantity() + 1);
        }

        CartProductItemDto cartProductItemDto = new CartProductItemDto();
        dbCartItem = selectOne(new CartItems().setProductItemId(productItemId).setUserId(userId));
        cartProductItemDto.setAmount(productItem.getPrice().multiply(new BigDecimal(dbCartItem.getQuantity())));
        cartProductItemDto.setQuantity(dbCartItem.getQuantity());
        return cartProductItemDto;
    }

    private void createCartItem(ProductItems productItem, Integer userId) {
        if (Objects.isNull(productItem)) {
            throw new ServiceException("E30001");
        }
        if (!existUser(userId)) {
            throw new ServiceException("E00106");
        }

        Date dbDate = dbService.toDbDate();
        Integer quantity = Objects.isNull(productItem.getMinQtyOnSell()) || productItem.getMinQtyOnSell().equals(0) ?
                1 : productItem.getMinQtyOnSell();
        CartItems cartItem = new CartItems()
                .setProductItemId(productItem.getId())
                .setUserId(userId)
                .setCreatedAt(dbDate)
                .setUpdatedAt(dbDate)
                .setQuantity(quantity);
        insertSelective(cartItem);
    }

    private void updateCartItemQuantity(Integer cartItemId, ProductItems productItem, Integer quantity) {
        if (Objects.isNull(productItem)) {
            throw new ServiceException("E30001");
        }

        if (quantity.compareTo(productItem.getMinQtyOnSell()) < 0) {
            throw new ServiceException("E30003", productItem.getMinQtyOnSell());
        }
        if (quantity.compareTo(productItem.getMaxQtyOnSell()) > 0) {
            throw new ServiceException("E30004", productItem.getMaxQtyOnSell());
        }

        CartItems cartItems = new CartItems()
                .setId(cartItemId)
                .setQuantity(quantity)
                .setUpdatedAt(dbService.toDbDate());

        updateSelectiveById(cartItems);
    }

    private boolean existUser(Integer userId) {
        return usersService.selectCount(new Users().setId(userId)) > 0;
    }

    private boolean existCartItem(Integer cartItemId) {
        return selectCount(new CartItems().setId(cartItemId)) > 0;
    }

    @Override
    public Integer deleteCartItem(Integer cartItemId, Integer userId) {
        if (!existUser(userId)) {
            throw new ServiceException("E00004");
        }
        deleteById(cartItemId);
        Integer sumQuantity = baseMapper.getCartItemQuantity(userId);
        return sumQuantity;
    }

    @Override
    public UpdateCartItemDto updateCartItem(Integer carItemId, Integer quantity, Integer userId) {
        CartItems dbCartItem = selectById(carItemId);
        ProductItems productItem = productItemsService.selectById(dbCartItem.getProductItemId());
        updateCartItemQuantity(carItemId, productItem, quantity);

        BigDecimal price = productItem.getPrice();
        UpdateCartItemDto updateCartItemDto = new UpdateCartItemDto();
        updateCartItemDto.setQuantity(quantity);
        updateCartItemDto.setSubtotal(price.multiply(new BigDecimal(quantity)));
        List<GetCartAmountDto> list = baseMapper.getCartItemAmount(userId);
        BigDecimal amount = BigDecimal.ZERO;
        BigDecimal temp = BigDecimal.ZERO;
        for (int i = 0; i < list.size(); i++) {
            temp = list.get(i).getPrice().multiply(new BigDecimal(list.get(i).getQuantity()));
            amount = amount.add(temp);
        }
        updateCartItemDto.setAmount(amount);
        return updateCartItemDto;
    }

    @Override
    public CartSettleDto settleCartItems(List<Integer> cartItemIds) {
        if (CollectionUtils.isEmpty(cartItemIds)) {
            return null;
        }

        CartSettleDto cartSettleDto = new CartSettleDto();
        List<OrderItemDto> orderItems = orderItemsService.getOrderItemByCartItemIds(cartItemIds);
        cartSettleDto.setOrderItems(orderItems);
        cartSettleDto.setReceivers(receiversService.selectList(null));
        cartSettleDto.setCartItemIds(cartItemIds);
        return cartSettleDto;
    }
}

